package com.hengpeng.msls.port.impl;

import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import com.google.gson.Gson;
import com.hengpeng.common.configuration.ConfigProvider;
import com.hengpeng.common.configuration.ConfigProviderFactory;
import com.hengpeng.common.constant.Constant;
import com.hengpeng.common.persist.QueryParameter;
import com.hengpeng.common.persist.QueryResult;
import com.hengpeng.common.persist.entity.AbstractEntity;
import com.hengpeng.common.persist.query.DynamicQuery;
import com.hengpeng.common.persist.query.Restrictions;
import com.hengpeng.itfinbase.message.ResponseMessage;
import com.hengpeng.itfinbase.message.TransMessage;
import com.hengpeng.msls.port.PortFactory;

@Component("portFactoryImpl")
@Lazy
public class PortFactoryImpl implements PortFactory, ApplicationContextAware {
    public final static Log logger = LogFactory.getLog(PortFactoryImpl.class);

    private final static ConfigProvider<String> cp = ConfigProviderFactory
            .getInstance(Constant.HP_COMMON_PROPERTIES_FILEPATH);

    private static HttpHeaders httpHeaders = null;

    private RestTemplate restTemplate = null;

    String DigestAuth_ClientId = "clientbasic";

    String DigestAuth_ClientPwd = "clientbasic4happycp";

    String DigestAuth_Key = "acegi";

    String DigestAuth_RealName = "Contacts Realm via Digest Authentication";

    public static HttpHeaders createBasicAuthHeaders(String userName, String password) {
        if (httpHeaders == null) {
            httpHeaders = new HttpHeaders();
            // Authorization
            String userPassword = userName + ":" + password;
            String encoding = new String(org.apache.commons.codec.binary.Base64.encodeBase64(userPassword.getBytes()),
                    Charset.forName("UTF-8"));
            httpHeaders.set("Authorization", "Basic " + encoding);
            // Accept
            List<MediaType> mediaTypes = new ArrayList<MediaType>();
            httpHeaders.setContentType(MediaType.APPLICATION_XML);
            mediaTypes.add(MediaType.APPLICATION_XML);
            // mediaTypes.add(MediaType.APPLICATION_JSON);
            httpHeaders.setAccept(mediaTypes);
            httpHeaders.set("Accept-Charset", "UTF-8");
        }
        return httpHeaders;
    }

    public <T> T doPostTrans(String transName, Class<T> returnType, Object parameter, Object... pathValue) {
        String url = cp.getConfigByPrimaryKey("remote.service.url") + "/RemoteService/" + transName;
        HttpEntity<Object> entity = new HttpEntity<Object>(parameter, createBasicAuthHeaders(DigestAuth_ClientId,
                DigestAuth_ClientPwd));
        return (T) restTemplate.postForEntity(url, entity, returnType, pathValue).getBody();
    }

    public <T extends AbstractEntity> Long count(Class<T> type, DynamicQuery query) {
        QueryParameter<T> queryParameters = new QueryParameter<T>();
        queryParameters.setType(type);
        queryParameters.setCustomQuery(query);
        QueryResult<?> doPostTrans = this.remoteQuery(queryParameters);
        return (Long) doPostTrans.getResults().get(0);
    }

    @SuppressWarnings("unchecked")
    public <T extends AbstractEntity> List<Object> findObject(Class<T> type, DynamicQuery query) {
        QueryParameter<T> queryParameters = new QueryParameter<T>();
        queryParameters.setType(type);
        queryParameters.setCustomQuery(query);
        QueryResult<?> doPostTrans = this.remoteQuery(queryParameters);
        return (List<Object>) doPostTrans.getResults();
    }

    public <T extends AbstractEntity> T getEntity(DynamicQuery query, Class<T> clz) {
        List<T> list = queryList(query, clz);
        return list != null && list.size() > 0 ? list.get(0) : null;
    }

    public <T extends AbstractEntity> T getEntityById(Object id, Class<T> clz) {
        if (id == null) {
            return null;
        }
        DynamicQuery query = new DynamicQuery(clz);
        query.add(Restrictions.eq("id", id));
        return getEntity(query, clz);
    }

    @SuppressWarnings("rawtypes")
    public Integer getSingleInteger(DynamicQuery query) {
        List list = queryList(query, null);
        if (list.size() > 0) {
            if (list.get(0) != null) {
                return Integer.parseInt(list.get(0).toString());
            } else {
                return null;
            }
        }
        return null;
    }

    public <T extends AbstractEntity> List<T> queryList(DynamicQuery query, Class<T> clz) {
        QueryParameter<T> qp = new QueryParameter<T>();
        qp.setCustomQuery(query);
        qp.setType(clz);
        List<T> result = remoteQuery(qp).getResults();
        return result == null ? new ArrayList<T>() : result;
    }

    @Override
    public <T extends AbstractEntity> QueryResult<T> remoteQuery(DynamicQuery query, Class<T> clz) {
        QueryParameter<T> qp = new QueryParameter<T>();
        qp.setCustomQuery(query);
        qp.setType(clz);
        return this.remoteQuery(qp);
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T extends AbstractEntity> QueryResult<T> remoteQuery(QueryParameter<T> queryParameters) {
        QueryResult<T> doPostTrans = this.doPostTrans("remoteQuery", QueryResult.class, queryParameters);
        if (!doPostTrans.getIsSuccess()) {
            logger.error("远程查询请求处理错误, Query{" + queryParameters.getCustomQuery().getSqlResult().getSql()
                    + "}, Parameter{" + queryParameters.getCustomQuery().getSqlResult().getParamsList() + "}");
        }
        return doPostTrans;
    }

    @Override
    public ResponseMessage remoteTrans(TransMessage transMessage) {
        Gson gson = new Gson();
        logger.info("远程交易请求,【transType=" + transMessage.getTransType() + "】,请求参数:{" + gson.toJson(transMessage) + "}");
        ResponseMessage doPostTrans = this.doPostTrans("remoteTrans", ResponseMessage.class, transMessage);
        logger.info("远程交易请求,【transType=" + transMessage.getTransType() + "】,响应信息:{" + gson.toJson(doPostTrans) + "}");
        return doPostTrans;
    }

    public <T extends ResponseMessage> T remoteTrans(TransMessage transMessage, Class<T> clz) {
        return clz.cast(remoteTrans(transMessage));
    }

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        restTemplate = context.getBean(RestTemplate.class);
        DigestAuth_ClientId = cp.getConfigByPrimaryKey("DigestAuth_ClientId");
        DigestAuth_ClientPwd = cp.getConfigByPrimaryKey("DigestAuth_ClientPwd");
        DigestAuth_Key = cp.getConfigByPrimaryKey("DigestAuth_Key");
        DigestAuth_RealName = cp.getConfigByPrimaryKey("DigestAuth_RealName");
    }

    @SuppressWarnings("all")
    public List<Object> queryList(DynamicQuery query) {
        QueryParameter qp = new QueryParameter();
        qp.setCustomQuery(query);
        List<Object> result = remoteQuery(qp).getResults();
        return result == null ? new ArrayList<Object>() : result;
    }
}
